﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections.ObjectModel;
using System.Linq;
using System.ServiceModel;
using DXTools.Core;
using DXTools.Core.CrmSdk;
using DXTools.UI.Modules.ODataQueryDesigner.Model;


namespace DXTools.UI.Modules.ODataQueryDesigner.DataProviders
{
    public class CRMDataProvider : IDataProvider
    {



        #region contructors

        private Uri _server;

        /// <summary>
        /// Constructor
        /// </summary>
        public CRMDataProvider()
        {
            _server = new Uri(DXTools.Core.ClientScript.GetServerUrl());


        }

        #endregion




        #region private methods

        public void RetrieveEntities(AsyncCallback asyncCallback)
        {
            try
            {
                DXTools.Core.CrmSdk.IOrganizationService service = DXTools.Core.WCFHelper.GetConnection(_server);

                OrganizationRequest request = new OrganizationRequest();
                request.RequestName = "RetrieveAllEntities";
                request.Parameters = new ParameterCollection();
                request.Parameters.Add(new DXTools.Core.CrmSdk.KeyValuePair<string, object>("EntityFilters", EntityFilters.Entity));
                request.Parameters.Add(new DXTools.Core.CrmSdk.KeyValuePair<string, object>("RetrieveAsIfPublished", false));

                service.BeginExecute(request, asyncCallback, service);

            }
            catch (FaultException<OrganizationServiceFault> ex)
            {
                throw ex;
            }
        }





        /// <summary>
        /// Retrieves 
        /// </summary>
        /// <param name=ServerUrl">ServerUrl</param>
        public void RetrieveEntity(String EntityLogicalName, bool IncludeRelationships, AsyncCallback asyncCallback)
        {
            try
            {
                DXTools.Core.CrmSdk.IOrganizationService service = DXTools.Core.WCFHelper.GetConnection(_server);

                OrganizationRequest request = new OrganizationRequest();
                request.RequestName = "RetrieveEntity";
                request.Parameters = new ParameterCollection();
                request.Parameters.Add(new DXTools.Core.CrmSdk.KeyValuePair<string, object>("LogicalName", EntityLogicalName));
                if (IncludeRelationships)
                    request.Parameters.Add(new DXTools.Core.CrmSdk.KeyValuePair<string, object>("EntityFilters", EntityFilters.Attributes | EntityFilters.Relationships));
                else
                    request.Parameters.Add(new DXTools.Core.CrmSdk.KeyValuePair<string, object>("EntityFilters", EntityFilters.Attributes));

                request.Parameters.Add(new DXTools.Core.CrmSdk.KeyValuePair<string, object>("MetadataId", new Guid("00000000-0000-0000-0000-000000000000")));
                request.Parameters.Add(new DXTools.Core.CrmSdk.KeyValuePair<string, object>("RetrieveAsIfPublished", false));

                service.BeginExecute(request, asyncCallback, service);

            }
            catch (FaultException<OrganizationServiceFault> ex)
            {
                throw ex;
            }

        }




        #endregion


        #region AsyncCallback Methods

        public EntityClass RetrieveEntityAsyncCallback(IAsyncResult Result)
        {

            EntityClass entityTmp = new EntityClass("", "");

            IOrganizationService service = (IOrganizationService)Result.AsyncState;
            EntityMetadata data = (EntityMetadata)service.EndExecute(Result).Results[0].Value;


            if (data.Attributes != null)
            {

                entityTmp.Attributes.Add(new AttributeClass(new AttributeMetadata() { SchemaName = "(Select All)" }));

                var attributes = from a in data.Attributes
                                 orderby (a.DisplayName.UserLocalizedLabel != null) ? a.DisplayName.UserLocalizedLabel.Label : a.SchemaName
                                 where a.AttributeOf == null
                                 select a;

                foreach (var attribute in attributes)
                {
                    entityTmp.Attributes.Add(new AttributeClass(attribute));
                    entityTmp.SortByAttributes.Add(new AttributeClass(attribute));
                    entityTmp.FilterAttributes.Add(new AttributeClass(attribute));
                }

                //
                // Add first filter
                if (entityTmp.FilterAttributes.Count > 0)
                {
                    FilterClass filter = new FilterClass();
                    filter.Attributes = new AttributeClass[entityTmp.FilterAttributes.Count];
                    //entityTmp.FilterAttributes.CopyTo(filter.Attributes.OrderBy(x=>x.UserLocalizedLabel).ToArray(), 0);
                    entityTmp.FilterAttributes.CopyTo(filter.Attributes, 0);
                    entityTmp.Filters.Add(filter);
                }


            }

            if (data.OneToManyRelationships != null)
            {
                var oneToManys = from a in data.OneToManyRelationships
                                 orderby a.SchemaName
                                 where a.IsValidForAdvancedFind.Value.Equals(true)
                                 select new { SchemaName = a.SchemaName, EntityLogicalName = a.ReferencingEntity };

                foreach (var oneToMany in oneToManys)
                {
                    entityTmp.Relationships_OneToMany.Add(new RelationshipClass(oneToMany.SchemaName, oneToMany.EntityLogicalName));

                }

            }

            if (data.ManyToOneRelationships != null)
            {
                var manyToOnes = from a in data.ManyToOneRelationships
                                 orderby a.SchemaName
                                 where a.IsValidForAdvancedFind.Value.Equals(true)
                                 select new { SchemaName = a.SchemaName, EntityLogicalName = a.ReferencedEntity };

                foreach (var manyToOne in manyToOnes)
                {
                    entityTmp.Relationships_ManyToOne.Add(new RelationshipClass(manyToOne.SchemaName, manyToOne.EntityLogicalName));
                }


            }

            if (data.ManyToManyRelationships != null)
            {
                var manyToManys = from a in data.ManyToManyRelationships
                                  orderby a.SchemaName
                                  where a.IsValidForAdvancedFind.Value.Equals(true)
                                  select new { SchemaName = a.SchemaName, EntityLogicalName = a.Entity2LogicalName };

                foreach (var manyToMany in manyToManys)
                {
                    entityTmp.Relationships_ManyToMany.Add(new RelationshipClass(manyToMany.SchemaName, manyToMany.EntityLogicalName));
                }

            }

            return entityTmp;

        }

        #endregion

    }
}
